#include <unistd.h>
#include "Log.h"
#include "MediaPlayer.h"
#include "AlsaAudioSink.h"

#ifdef RK
#include <drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#include "DRMVideoSink.h"
#else
#include "SDLVideoSink.h"
#endif

MediaPlayer::MediaPlayer()
{
	LOGI("MediaPlayer construct");
	init();
	changeToState(Player_State_Idle);
}

MediaPlayer::~MediaPlayer()
{
	LOGI("~MediaPlayer");
	stop();
	release();
}

void MediaPlayer::reset()
{
	LOGI("MediaPlayer reset");
	stop();
	release();
	init();
	changeToState(Player_State_Idle);
}

void MediaPlayer::release()
{
	LOGI("MediaPlayer release");
	stop();
	if(m_PMsgThread)
		delete m_PMsgThread;
	if(m_PDemuxThread)
		delete m_PDemuxThread;
	if(m_PVideoDecodeThread)
		delete m_PVideoDecodeThread;
	if(m_PAudioDecodeThread)
		delete m_PAudioDecodeThread;
	if(m_PVideoRefreshThread)
		delete m_PVideoRefreshThread;

	if(m_PVideoPacketQueue)
		delete m_PVideoPacketQueue;
	if(m_PAudioPacketQueue)
		delete m_PAudioPacketQueue;
	if(m_PVideoFrameQueue)
		delete m_PVideoFrameQueue;
	if(m_PAudioFrameQueue)
		delete m_PAudioFrameQueue;
	if(m_PMsgQueue)
		delete m_PMsgQueue;
	if(m_PDemux)
		delete m_PDemux;
	if(m_PVideoDecoder)
		delete m_PVideoDecoder;
	if(m_PAudioDecoder)
		delete m_PAudioDecoder;
	if(m_PAudioSink)
		delete m_PAudioSink;
	if(m_PVideoSink)
		delete m_PVideoSink;

	m_PMsgThread = NULL;
	m_PDemuxThread = NULL;
	m_PVideoDecodeThread = NULL;
	m_PAudioDecodeThread = NULL;
	m_PVideoRefreshThread = NULL;
	m_PAudioOutThread = NULL;

	m_PVideoPacketQueue = NULL;
	m_PAudioPacketQueue = NULL;
	m_PVideoFrameQueue = NULL;
	m_PAudioFrameQueue = NULL;
	m_PMsgQueue = NULL;
	m_PVideoDecoder = NULL;
	m_PAudioDecoder = NULL;
	changeToState(Player_State_End);
}

void MediaPlayer::init()
{
	m_PMsgThread = NULL;
	m_PDemuxThread = NULL;
	m_PVideoDecodeThread = NULL;
	m_PAudioDecodeThread = NULL;
	m_PVideoRefreshThread = NULL;

	m_PVideoPacketQueue = NULL;
	m_PAudioPacketQueue = NULL;
	m_PVideoFrameQueue = NULL;
	m_PAudioFrameQueue = NULL;
	m_PMsgQueue = NULL;
	m_PVideoDecoder = NULL;
	m_PAudioDecoder = NULL;

	m_PlayerAbortRequest = false;
	m_Prepared = false;
	m_VideoDisCB = NULL;
	m_AudioOutCB = NULL;
	m_EventCB = NULL;

	m_AudioFuncPause = NULL;
	m_AudioFuncPlay = NULL;
	m_AudioFuncFlush = NULL;
	m_AudioFuncSetSpeed = NULL;
	m_AudioCBPara = NULL;
	m_AudioConvertCtx = NULL;
	m_AudioBuff = NULL;
	m_AudioOutBuffSize = 0;

	m_PVideoSink = NULL;
	m_PAudioSink = NULL;

	m_SeekRequest = false;
	m_SeekPos = 0;
	m_Width = 0;
	m_Height = 0;

	m_PauseRequest = false;
	m_CurrentAudioPts = 0.0;
	m_Restart = false;

	m_AudioPktUnderrun = false;

	m_FirstVideoRendered = false;
	m_FirstAudioRendered = false;

	m_VideoHide = false;

	m_PlayerOpt.av_class = &player_context_class;
	m_PlayerOpt.opts = NULL;
	av_opt_set_defaults(&m_PlayerOpt);
	memset(&m_AudioFilter, 0, sizeof(m_AudioFilter));
	setVolume(20);

	static bool init_ffmpeg = false;
	if(!init_ffmpeg) {
		av_log_set_level(AV_LOG_INFO);
		av_log_set_callback(logCallBack);
		// av_register_all();
		avformat_network_init();
		init_ffmpeg = true;
	}
	m_PMsgThread = new Thread(msgLoopThread, "msg_loop", this);
	m_PDemuxThread = new Thread(demuxThread, "demux_thread", this);
	m_PVideoDecodeThread = new Thread(videoDecodeThread, "video_decode", this);
	m_PAudioDecodeThread = new Thread(audioDecodeThread, "audio_decode", this);
	m_PVideoRefreshThread = new Thread(videoRefreshThread, "video_refresh", this);
	m_PAudioOutThread = new Thread(audioOutThread, "audio_out", this);

	//初始化解码队列和消息队列
	m_PVideoPacketQueue = new PacketQueue();
	m_PAudioPacketQueue = new PacketQueue();
	m_PMsgQueue = new MessageQueue();
	m_PDemux = new Demuxer();
	if(!m_PMsgThread || !m_PDemuxThread || !m_PVideoDecodeThread || !m_PAudioDecodeThread ||\
	   !m_PVideoRefreshThread || !m_PAudioOutThread || !m_PVideoPacketQueue || !m_PAudioPacketQueue ||\
	   !m_PMsgQueue || !m_PDemux) {
		LOGE("init error!");
	}
}

void MediaPlayer::stop()
{
	LOGI("stop");

	Ret_If_State_Eq(Player_State_Idle);
	Ret_If_State_Eq(Player_State_Initialized);
	// Ret_If_State_Eq(Player_State_Async_Preparing);
	// Ret_If_State_Eq(Player_State_Prepared);
	// Ret_If_State_Eq(Player_State_Started);
	// Ret_If_State_Eq(Player_State_Paused);
	// Ret_If_State_Eq(Player_State_Completed);
	Ret_If_State_Eq(Player_State_Stoped);
	// Ret_If_State_Eq(Player_State_Error);
	Ret_If_State_Eq(Player_State_End);

	/*先暂停*/
	m_PauseRequest = true;
	audioOperate(Audio_Operate_Pause);

	/********************等待所有线程退出*****************/

	if(!m_PMsgThread->isExited()) {
		LOGI("wait for %s(%ld)",m_PMsgThread->m_name, m_PMsgThread->tid);
		m_PMsgQueue->abort();
		m_PMsgThread->wait();
	}

	if(!m_PDemuxThread->isExited()) {
		LOGI("wait for %s(%ld)", m_PDemuxThread->m_name, m_PDemuxThread->tid);
		playerAbortRequest();
		m_PDemuxThread->wait();
	}

	if(!m_PVideoRefreshThread->isExited()) {
		LOGI("wait for %s(%ld)", m_PVideoRefreshThread->m_name, m_PVideoRefreshThread->tid);
		m_PVideoFrameQueue->abort();
		m_PVideoRefreshThread->wait();
	}

	if(!m_PAudioOutThread->isExited()) {
		LOGI("wait for %s(%ld)", m_PAudioOutThread->m_name, m_PAudioOutThread->tid);
		m_PAudioFrameQueue->abort();
		m_PAudioOutThread->wait();
	}

	if(!m_PVideoDecodeThread->isExited()) {
		LOGI("wait for %s(%ld)", m_PVideoDecodeThread->m_name, m_PVideoDecodeThread->tid);
		m_PVideoPacketQueue->abort();
		m_PVideoDecodeThread->wait();
	}

	if(!m_PAudioDecodeThread->isExited()) {
		LOGI("wait for %s(%ld)", m_PAudioDecodeThread->m_name, m_PAudioDecodeThread->tid);
		m_PAudioPacketQueue->abort();
		m_PAudioDecodeThread->wait();
	}

	changeToState(Player_State_Stoped);
}

void MediaPlayer::playerAbortRequest()
{
	AutoLock lock(&m_PlayerMutex);
	m_PlayerAbortRequest = true;
	//m_MsgCond.notify();
}

void MediaPlayer::setDataSource(const char *url)
{
	LOGI("setDataSource url:%s", url);
	if(!url) {
		LOGE("url is null!");
		return;
	}
	//Ret_If_State_Eq(Player_State_Idle);
	Ret_If_State_Eq(Player_State_Initialized);
	Ret_If_State_Eq(Player_State_Async_Preparing);
	Ret_If_State_Eq(Player_State_Prepared);
	Ret_If_State_Eq(Player_State_Started);
	Ret_If_State_Eq(Player_State_Paused);
	Ret_If_State_Eq(Player_State_Completed);
	Ret_If_State_Eq(Player_State_Stoped);
	Ret_If_State_Eq(Player_State_Error);
	Ret_If_State_Eq(Player_State_End);
	m_Url = url;

	changeToState(Player_State_Initialized);
	LOGI("setDataSource leave");
}

void MediaPlayer::prepareASync()
{
	LOGI("prepareASync enter");
	Ret_If_State_Eq(Player_State_Idle);
	//Ret_If_State_Eq(Player_State_Initialized);
	Ret_If_State_Eq(Player_State_Async_Preparing);
	Ret_If_State_Eq(Player_State_Prepared);
	Ret_If_State_Eq(Player_State_Started);
	Ret_If_State_Eq(Player_State_Paused);
	Ret_If_State_Eq(Player_State_Completed);
	// Ret_If_State_Eq(Player_State_Stoped);
	Ret_If_State_Eq(Player_State_Error);
	Ret_If_State_Eq(Player_State_End);
	changeToState(Player_State_Async_Preparing);
	// prepareAsync_l();

	av_opt_set_dict(&m_PlayerOpt, &m_PlayerOpt.opts);
	m_PVideoFrameQueue = new FrameQueue(m_PlayerOpt.pictq_size);
	m_PAudioFrameQueue = new FrameQueue(m_PlayerOpt.audioframe_size);
	showOpts();
	showOption();

	m_PDemux->setUrl((char *)m_Url.c_str());
    m_PDemux->registerInterruptCB(decode_interrupt_cb, this);
    m_PDemuxThread->start();
    m_PMsgThread->start();
    LOGI("prepareASync leave");
}

void MediaPlayer::seek(int second)
{
	LOGI("seek");
	Ret_If_State_Eq(Player_State_Idle);
	Ret_If_State_Eq(Player_State_Initialized);
	Ret_If_State_Eq(Player_State_Async_Preparing);
	// Ret_If_State_Eq(Player_State_Prepared);
	// Ret_If_State_Eq(Player_State_Started);
	// Ret_If_State_Eq(Player_State_Paused);
	// Ret_If_State_Eq(Player_State_Completed);
	Ret_If_State_Eq(Player_State_Stoped);
	Ret_If_State_Eq(Player_State_Error);
	Ret_If_State_Eq(Player_State_End);

	postEvent(Player_Evt_Seek, second);
}

void MediaPlayer::start()
{
	LOGI("start");
	Ret_If_State_Eq(Player_State_Idle);
	Ret_If_State_Eq(Player_State_Initialized);
	Ret_If_State_Eq(Player_State_Async_Preparing);
	// Ret_If_State_Eq(Player_State_Prepared);
	Ret_If_State_Eq(Player_State_Started);
	// Ret_If_State_Eq(Player_State_Paused);
	// Ret_If_State_Eq(Player_State_Completed);
	Ret_If_State_Eq(Player_State_Stoped);
	Ret_If_State_Eq(Player_State_Error);
	Ret_If_State_Eq(Player_State_End);

	postEvent(Player_Evt_Start);
	// changeToState(Player_State_Started);
}

void MediaPlayer::pause()
{
	LOGI("pause");
	Ret_If_State_Eq(Player_State_Idle);
	Ret_If_State_Eq(Player_State_Initialized);
	Ret_If_State_Eq(Player_State_Async_Preparing);
	// Ret_If_State_Eq(Player_State_Prepared);
	// Ret_If_State_Eq(Player_State_Started);
	Ret_If_State_Eq(Player_State_Paused);
	// Ret_If_State_Eq(Player_State_Completed);
	Ret_If_State_Eq(Player_State_Stoped);
	Ret_If_State_Eq(Player_State_Error);
	Ret_If_State_Eq(Player_State_End);

	postEvent(Player_Evt_Pause);
	// changeToState(Player_State_Paused);
}

bool MediaPlayer::isPlaying()
{
    if (m_State == Player_State_Prepared ||
        m_State == Player_State_Started) {
        return true;
    }
    return false;
}

/*volume 0-100*/
#define MAX_VOLUME 10.0
void MediaPlayer::setVolume(int volume)
{
	if(volume > 100)
		volume = 100;
	if(volume < 0)
		volume = 0;
	m_Volume = volume;
	//最大值MAX_VOLUME，否则声音要失真
	double dvolume = m_Volume*MAX_VOLUME/100.0;
	char volume_buf[10];
	snprintf(volume_buf, 10, "%lf", dvolume);
	if(m_AudioFilter.volume_ctx) {
		LOGI("volume:%s", volume_buf);
		avfilter_process_command(m_AudioFilter.volume_ctx, "volume", volume_buf, 0, 0, 0);
	}
}

void MediaPlayer::postEvent(Player_Event evt, int arg1, int arg2)
{
	Message msg;
	msg.what = evt;
	msg.arg1 = arg1;
	msg.arg2 = arg2;
	m_PMsgQueue->post(msg);
}

void MediaPlayer::changeToState(Player_State state)
{
	AutoLock lock(&m_PlayerMutex);
	LOGI("State Changed %s --> %s", getStateName(m_State), getStateName(state));
	m_State = state;
}

void MediaPlayer::setOption(const char *key, int value)
{
	av_dict_set_int(&m_PlayerOpt.opts, key, value, 0);
}

void MediaPlayer::setOption(const char *key, const char *value)
{
	av_dict_set(&m_PlayerOpt.opts, key, value, 0);
}

void MediaPlayer::showOpts()
{
	LOGI("loop:%d", m_PlayerOpt.loop);
	LOGI("infinite_buffer:%d", m_PlayerOpt.infinite_buffer);
	LOGI("framedrop:%d", m_PlayerOpt.framedrop);
	LOGI("seek_at_start:%ds", m_PlayerOpt.start_time);
	LOGI("start_on_prepared:%d", m_PlayerOpt.start_on_prepared);
	LOGI("pictq_size:%d", m_PlayerOpt.pictq_size);
	LOGI("audioframe_size:%d", m_PlayerOpt.audioframe_size);
	LOGI("max_buffer_size:%dKb", m_PlayerOpt.max_buffer_size/1024);
}

void MediaPlayer::showOption()
{
    AVDictionaryEntry *t = NULL;
    // av_dict_set(&m_PlayerOpt.opts, "key", "value", 0);

    while ((t = av_dict_get(m_PlayerOpt.opts, "", t, AV_DICT_IGNORE_SUFFIX))) {
        LOGD("%s = %s", t->key, t->value);
    }
}

const char* MediaPlayer::getEventName(Player_Event evt)
{
	switch(evt) {
		case Player_Evt_Flush:
			return "Flush";
		case Player_Evt_Error:
			return "Error";
		case Player_Evt_PrePared:
			return "PrePared";
		case Player_Evt_Completed:
			return "Completed";
		case Player_Evt_SeekCompleted:
			return "Seek Completed";
		case Player_Evt_OpenInput:
			return "Open Input";
		case Player_Evt_FindStreamInfo:
			return "Find Stream Info";
		case Player_Evt_Seek:
			return "Seek";
		case Player_Evt_Pause:
			return "Pause";
		case Player_Evt_Start:
			return "Start";
		case Player_Evt_VideoChanged:
			return "VideoChanged";
		case Player_Evt_VideoRenderStart:
			return "Video Rendering Start";
		case Player_Evt_AudioRenderStart:
			return "Audio Rendering Start";
		default:
			LOGE("unkown event %d!", evt);
			return "unkown event";
	}
}

const char* MediaPlayer::getStateName(Player_State state)
{
	switch(state) {
		case Player_State_Idle:
			return "Idle";
		case Player_State_Initialized:
			return "Initialized";
		case Player_State_Async_Preparing:
			return "Async_Preparing";
		case Player_State_Prepared:
			return "Prepared";
		case Player_State_Started:
			return "Started";
		case Player_State_Paused:
			return "Paused";
		case Player_State_Completed:
			return "Completed";
		case Player_State_Stoped:
			return "Stoped";
		case Player_State_Error:
			return "Error";
		case Player_State_End:
			return "End";
		default:
			LOGE("unkown state");
			return NULL;
	}
}

const char* MediaPlayer::getErrorInfo(Player_Error err)
{
	switch(err) {
		case Player_Error_DemuxOpen:
			return "demux open error";
		case Player_Error_DecoderOpen:
			return "decoder open error";
		case Player_Error_AudioInit:
			return "audio init error";
		default:
			LOGE("unkown error %d!", err);
			return "unkown error";
	}
}

float MediaPlayer::getPropertyFloat(Player_Property id)
{
	switch(id) {
		case Player_Property_Float_PlayBackRate:
			return 1.0;
		case Player_Property_Float_AVDiff:
			return 0;
		case Player_Property_Float_DropFrameRate:
			return 0;
		case Player_Property_Float_FPS:
			return (float)m_PDemux->m_VideoFPS;
		default:
			LOGE("unkown property");
			return 0;
	}
}

int MediaPlayer::getPropertyInt(Player_Property id)
{
	switch(id) {
		case Player_Property_Int_PlayBackVolume:
			return 0;
		case Player_Property_Int_VideoDecoder:
			return m_PDemux->m_VideoCodec;
		case Player_Property_Int_VideoCachedDuration:
			return m_PVideoPacketQueue->duration();
		case Player_Property_Int_VideoCachedBytes:
			return m_PVideoPacketQueue->size();
		case Player_Property_Int_VideoCachedPackets:
			return m_PVideoPacketQueue->nb_pkt();
		case Player_Property_Int_VideoHeight:
			return m_PDemux->m_VideoHeight;
		case Player_Property_Int_VideoWidth:
			return m_PDemux->m_VideoWidth;
		case Player_Property_Int_VideoFormat:
			return m_PDemux->m_VideoFormat;
		case Player_Property_Int_VideoBitRate:
			return m_PDemux->m_VideoBitRate;
		case Player_Property_Int_AudioStream:
			return m_PDemux->m_AudioStream;
		case Player_Property_Int_AudioDecoder:
			return m_PDemux->m_AudioCodec;
		case Player_Property_Int_AudioCachedDuration:
			return m_PAudioPacketQueue->duration();
		case Player_Property_Int_AudioCachedBytes:
			return m_PAudioPacketQueue->size();
		case Player_Property_Int_AudioCachedPackets:
			return m_PAudioPacketQueue->nb_pkt();
		case Player_Property_Int_AudioSampleRate:
			return m_PDemux->m_AudioSampleRate;
		case Player_Property_Int_AudioFrameSize:
			return m_PDemux->m_AudioFrameSize;
		case Player_Property_Int_AudioChannels:
			return m_PDemux->m_AudioChannels;
		case Player_Property_Int_AudioChannelLayout:
			return m_PDemux->m_AudioChannelLayout;
		case Player_Property_Int_AudioFormat:
			return m_PDemux->m_AudioFormat;
		case Player_Property_Int_AudioBitRate:
			return m_PDemux->m_AudioBitRate;
		case Player_Property_Int_Duration:
			return m_PDemux->m_Duration;
		default:
			LOGE("unkown property");
			return 0;
	}
}

void MediaPlayer::call_external_cb(Message &msg)
{
	/*回调外部注册的事件函数*/
	event_callback handle_message = m_EventCB;
	if(handle_message)
		handle_message(&msg, m_EventPara);
}

void MediaPlayer::handle_msg_internal(Message &msg)
{
	switch(msg.what) {
		case Player_Evt_Flush:
			break;
		case Player_Evt_Error:
			changeToState(Player_State_Error);
			break;
		case Player_Evt_PrePared:
			changeToState(Player_State_Prepared);
			break;
		case Player_Evt_Completed:
			/*播放完成后调start从头开始播*/
			m_Restart = true;
			changeToState(Player_State_Completed);
			break;
		case Player_Evt_Seek:
			m_SeekRequest = true;
			m_SeekPos = msg.arg1;
			break;
		case Player_Evt_Pause:
			/*video refresh线程暂停，导致video thread解码线程阻塞，packetqueue满导致导致read_thread阻塞*/
			m_PauseRequest = true;
			/*调用外部注册的音频Pause函数，导致audio thread解码线程阻塞，packetqueue满导致read_thread阻塞*/
			audioOperate(Audio_Operate_Pause);
			changeToState(Player_State_Paused);
			break;
		case Player_Evt_Start:
			/*播放完成后调start从头开始播*/
			if(m_Restart) {
				m_PDemux->seek(0);
				m_Restart = false;
			}
			m_PauseRequest = false;
			audioOperate(Audio_Operate_Play);
			changeToState(Player_State_Started);
			break;
	}
}

int MediaPlayer::msgLoopThread(void *lpara)
{
	MediaPlayer *player = (MediaPlayer *)lpara;
	player->message_loop();
	return 0;
}

int MediaPlayer::message_loop()
{
	// player->m_PMsgThread->setThreadPriority(Thread::THREAD_PRIORITY_HIGH);
	while(true) {
		Message msg;
		int ret = m_PMsgQueue->get(msg);
		if(ret < 0)
			break;
		LOGI("message loop, receive message, size:%d what:%s:%d arg1:%d arg2:%d", m_PMsgQueue->size(), getEventName((Player_Event)msg.what),msg.what, msg.arg1, msg.arg2);

		handle_msg_internal(msg);

		//handle msg
		switch(msg.what) {
			case Player_Evt_Flush:
				break;
			case Player_Evt_Error:
				call_external_cb(msg);
				break;
			case Player_Evt_PrePared:
				call_external_cb(msg);
				//等待外部prepared返回后再开始音频play，外部需要在prepared后得到音频参数后才能初始化音视频播放设备
				if(m_PlayerOpt.start_on_prepared) {
					audioOperate(Audio_Operate_Play);
				}
				break;
			case Player_Evt_Completed:
				call_external_cb(msg);
			case Player_Evt_AudioRenderStart:
				call_external_cb(msg);
			case Player_Evt_VideoRenderStart:
				call_external_cb(msg);
				break;
		}
	}
	return 0;
}

int MediaPlayer::decode_interrupt_cb(void *ctx)
{
    MediaPlayer *player = (MediaPlayer *)ctx;
    return player->m_PlayerAbortRequest ? 1 : 0;
}

int MediaPlayer::demuxThread(void *lpara)
{
	MediaPlayer *player = (MediaPlayer *)lpara;
	player->demux_thread();
	return 0;
}

void MediaPlayer::bufferingControl()
{
#if 0
	int audio_buffer_duration = 0;//ms
	int video_buffer_duration = 0;
	AVRational audioTb = m_PDemux->m_AudioTimeBase;
	AVRational videoTb = m_PDemux->m_VideoTimeBase;

	int max_buffer_duration = m_PlayerOpt.max_buffer_duration; 
	int min_buffer_duration = m_PlayerOpt.min_buffer_duration;
	int max_buffer_size = m_PlayerOpt.max_buffer_size;

    //控制buffer duration
    audio_buffer_duration = ((float)m_PAudioPacketQueue->duration() * \
    	(audioTb.num && audioTb.den ? av_q2d(audioTb) : 0)) * 1000;
    video_buffer_duration = ((float)m_PVideoPacketQueue->duration() * \
    	(videoTb.num && videoTb.den ? av_q2d(videoTb) : 0)) * 1000;

    int buffer_duration = audio_buffer_duration > video_buffer_duration ? audio_buffer_duration : video_buffer_duration;

    LOGD("a:%d v:%d\r",m_PAudioPacketQueue->nb_pkt(), m_PVideoPacketQueue->nb_pkt());

    if((m_PAudioPacketQueue->nb_pkt() <= 35) && !isbuffering && \
    	(m_State == Player_State_Started || m_State == Player_State_Paused)) {
    	pause();
    	LOGD("pause");
    	isbuffering = true;
    }

    if((m_PAudioPacketQueue->nb_pkt() >= 50) && isbuffering &&\
    	(m_State == Player_State_Started || m_State == Player_State_Paused)) {
    	start();
    	LOGD("start");
    	isbuffering = false;

    }

    if(m_PAudioPacketQueue->nb_pkt() >= 50) {
    	continue;
    }

    LOGD("a:%d v:%d b:%d   ",audio_buffer_duration, video_buffer_duration, buffer_duration);

    if((buffer_duration <= 50) && !isbuffering && \
    	(m_State == Player_State_Started || m_State == Player_State_Paused)) {
    	pause();
    	LOGD("pause");
    	isbuffering = true;
    }

    if((buffer_duration >= 500) && isbuffering &&\
    	(m_State == Player_State_Started || m_State == Player_State_Paused)) {
    	start();
    	LOGD("start");
    	isbuffering = false;

    }

	if(buffer_duration > 500) {
		continue;
	}
#endif
}

#define FFERR2STR(ERRNUM) av_make_error_string(errbuf, 100, ERRNUM)

int MediaPlayer::demux_thread()
{
	videoinit_callback init_video = m_VideoInitCB;
	audio_operate_callback init_audio = m_AudioFuncInit;
	int ret = 0;
	ret = m_PDemux->open();
	if(ret != 0) {
		LOGE("demux open failed");
		postEvent(Player_Evt_Error, Player_Error_DemuxOpen, ret);
		return -1;
	}

	m_PVideoDecoder = new Decoder(m_PDemux->getContext(), Decoder::MEDIA_TYPE_VIDEO, \
								  m_PDemux->getVideoStream(), m_PVideoPacketQueue);
	ret = m_PVideoDecoder->open();
	if(ret != 0) {
		LOGE("video decoder open failed");
		postEvent(Player_Evt_Error, Player_Error_DecoderOpen, ret);
		return -1;
	}

	m_PAudioDecoder = new Decoder(m_PDemux->getContext(), Decoder::MEDIA_TYPE_AUDIO, \
		                          m_PDemux->getAudioStream(), m_PAudioPacketQueue);
	ret = m_PAudioDecoder->open();
	if(ret != 0) {
		LOGE("video decoder open failed");
		postEvent(Player_Evt_Error, Player_Error_DecoderOpen, ret);
		return -1;
	}

	m_PDemux->dumpFormat();

	//调用外部提供的初始化音频和视频接口，此时音频和视频的参数(如音频的采样率，视频的分辨率等)都已解出，
	//可以初始化音视频播放设备了
	if(!init_video || !init_audio) {
		LOGE("init_video(%p), init_audio(%p)", init_video, init_audio);
	}
	if(init_video)
		init_video(m_VideoInitPara, NULL);
	if(init_audio)
		init_audio(m_AudioInitPara, NULL);

	m_Width = getPropertyInt(Player_Property_Int_VideoWidth);
	m_Height = getPropertyInt(Player_Property_Int_VideoHeight);

	m_PVideoDecodeThread->start();
	m_PAudioDecodeThread->start();
    m_PAudioOutThread->start();
    m_PVideoRefreshThread->start();

	//发出准备完成事件,播放器初始化完成，接下来可以播放了
	postEvent(Player_Evt_PrePared);

	/*prepared后是否自动播放*/
	m_PauseRequest = !m_PlayerOpt.start_on_prepared;
	if (!m_PlayerOpt.start_on_prepared) {
		changeToState(Player_State_Paused);
        while (m_PauseRequest && !m_PlayerAbortRequest) {
            usleep(20000);
        }
    }
    postEvent(Player_Evt_Start);
    // changeToState(Player_State_Started);

    /*Prepared状态下调用seek*/
    if(m_SeekRequest) {
    	m_PDemux->seek(m_SeekPos);
    	m_SeekRequest = false;
    }

    /*从指定位置开始播放*/
    if(m_PlayerOpt.start_time) {
    	m_PDemux->seek(m_PlayerOpt.start_time);
    }

	AVPacket pkt;

	bool complete = false;
	int audio_buffer_duration = 0;//ms
	int video_buffer_duration = 0;
	AVRational audioTb = m_PDemux->m_AudioTimeBase;
	AVRational videoTb = m_PDemux->m_VideoTimeBase;
	bool isbuffering = false;
	m_AudioPktUnderrun = false;
	int audio_pause_cnt = 0;
	char errbuf[100];
	int min_audio_pkt = m_PlayerOpt.min_audio_pkt;
	int max_audio_pkt = m_PlayerOpt.max_audio_pkt;
	int max_buffer_duration = m_PlayerOpt.max_buffer_duration; 
	int min_buffer_duration = m_PlayerOpt.min_buffer_duration;
	int max_buffer_size = m_PlayerOpt.max_buffer_size;
	while(true) {
		if (m_PlayerAbortRequest)
            break;

        /*处理seek请求*/
        if(m_SeekRequest) {
        	m_PDemux->seek(m_SeekPos);
        	m_SeekRequest = false;
        	complete = false;
        	m_PVideoPacketQueue->clear();
        	m_PVideoPacketQueue->addFlushPkt();

        	m_PAudioPacketQueue->clear();
        	m_PAudioPacketQueue->addFlushPkt();

        	postEvent(Player_Evt_SeekCompleted);
        }
        

        //控制buffer duration
        // audio_buffer_duration = ((float)m_PAudioPacketQueue->duration() * \
        // 	(audioTb.num && audioTb.den ? av_q2d(audioTb) : 0)) * 1000;
        // video_buffer_duration = ((float)m_PVideoPacketQueue->duration() * \
        // 	(videoTb.num && videoTb.den ? av_q2d(videoTb) : 0)) * 1000;

        // int buffer_duration = audio_buffer_duration > video_buffer_duration ? audio_buffer_duration : video_buffer_duration;

    	//使缓存帧数保存在min_packet - max_packet内
        if((m_PAudioPacketQueue->nb_pkt() < min_audio_pkt) && !isbuffering && \
        	(m_State == Player_State_Started || m_State == Player_State_Paused)) {
        	m_AudioPktUnderrun = true;
        	isbuffering = true;
        	audio_pause_cnt++;
        }
        if((m_PAudioPacketQueue->nb_pkt() >= max_audio_pkt) && isbuffering &&\
        	(m_State == Player_State_Started || m_State == Player_State_Paused)) {
        	m_AudioPktUnderrun = false;
        	isbuffering = false;
        }

        if(m_PAudioPacketQueue->nb_pkt() > max_audio_pkt) {
        	usleep(5000);
        	continue;
        }

        //限制buffer最大值
        if(!m_PlayerOpt.infinite_buffer && 
        	(m_PVideoPacketQueue->size() + m_PAudioPacketQueue->size() >= max_buffer_size)) {
	       	usleep(10000);
	    	continue;
        }

        ret = m_PDemux->readPacket(pkt);

        if(ret < 0) {
        	LOGE("ret:%d %s", FFERR2STR(ret));
        	/*是否循环播放*/
        	if(ret == AVERROR_EOF) {
        		if(!m_PlayerOpt.loop) {
        			int curpos = getCurrentPosition() / 1000;
        			if((curpos >= getDuration() - 1) && !complete) {
        				LOGI("curpos:%d duration:%d", getCurrentPosition()/1000, getDuration());
        				complete = true;
        				postEvent(Player_Evt_Completed);
        			}
        			usleep(10000);
        			continue;
        		}
        		m_PDemux->seek(0);
        		usleep(10000);
        		continue;
        	}
        	LOGE("ret < 0, break");
        	break;
        }

        if(m_PDemux->isVideoPacket(pkt)) {
        	// LOGD("read video pkt, keyframe:%d size:%d nb:%d pts:%ld", m_PDemux->isKeyFrame(pkt), \
        	// 	pkt.size, m_PVideoPacketQueue->nb_pkt(), pkt.pts);
        	m_PVideoPacketQueue->add(pkt);
        }

        if(m_PDemux->isAudioPacket(pkt)) {
        	m_PAudioPacketQueue->add(pkt);
        	// LOGD("read audio pkt, size:%d nb:%d pts:%ld", pkt.size, m_PAudioPacketQueue->nb_pkt(), pkt.pts);
        }
	}

fail:

    if (!m_PlayerAbortRequest) {
    	LOGE("player abort");
        postEvent(Player_Evt_Error);
    }
	return 0;
}

//输出固定S16,双声道
#define OUT_SAMPLE_FMT AV_SAMPLE_FMT_S16
#define OUT_CHANNEL_LAYOUT AV_CH_LAYOUT_STEREO
#define OUT_CHANNEL 2
#define OUT_SAMPLE_RATE 44100
// #define VOLUME_VAL 2.0

//(input) -> abuffer -> volume -> aformat -> abuffersink -> (output)
/*refer to ffmpeg-4.1.3/doc/examples/filter_audio.c*/
int MediaPlayer::initAudioFilterGraph(int in_sample_rate, int in_format, int in_channel_layout, \
							int out_sample_rate, int out_format, int out_channel_layout)
{
    AVDictionary *options_dict = NULL;
    uint8_t options_str[1024];
    uint8_t ch_layout[64];

    int err;
	// int in_sample_rate = getPropertyInt(Player_Property_Int_AudioSampleRate);
	// int in_format = getPropertyInt(Player_Property_Int_AudioFormat);
	// int in_channel_layout = getPropertyInt(Player_Property_Int_AudioChannelLayout);

	// int out_sample_rate = in_sample_rate;
	char errbuf[100];
	if(m_Volume > 100)
		m_Volume = 100;
	if(m_Volume < 0)
		m_Volume = 0;
	double volume = m_Volume*MAX_VOLUME/100.0;
	char volume_buf[10];
	snprintf(volume_buf, 10, "%lf", volume);

    /* Create a new filtergraph, which will contain all the filters. */
    m_AudioFilter.filter_graph = avfilter_graph_alloc();
    // m_AudioFilter.filter_graph->execute = avfilter_execute;
    if (!m_AudioFilter.filter_graph) {
        LOGE("Unable to create filter graph. %s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* Create the m_AudioFilter.abuffer filter;
     * it will be used for feeding the data into the graph. */
    m_AudioFilter.abuffer = avfilter_get_by_name("abuffer");
    if (!m_AudioFilter.abuffer) {
        LOGE("Could not find the abuffer filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    m_AudioFilter.abuffer_ctx = avfilter_graph_alloc_filter(m_AudioFilter.filter_graph, m_AudioFilter.abuffer, "src");
    if (!m_AudioFilter.abuffer_ctx) {
        LOGE("Could not allocate the abuffer instance.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* Set the filter options through the AVOptions API. */
    av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, in_channel_layout);
    av_opt_set    (m_AudioFilter.abuffer_ctx, "channel_layout", ch_layout,                            AV_OPT_SEARCH_CHILDREN);
    av_opt_set    (m_AudioFilter.abuffer_ctx, "sample_fmt",     av_get_sample_fmt_name(in_format),    AV_OPT_SEARCH_CHILDREN);
    av_opt_set_q  (m_AudioFilter.abuffer_ctx, "time_base",      (AVRational){ 1, in_sample_rate },    AV_OPT_SEARCH_CHILDREN);
    av_opt_set_int(m_AudioFilter.abuffer_ctx, "sample_rate",    in_sample_rate,                       AV_OPT_SEARCH_CHILDREN);

    /* Now initialize the filter; we pass NULL options, since we have already
     * set all the options above. */
    err = avfilter_init_str(m_AudioFilter.abuffer_ctx, NULL);
    if (err < 0) {
        LOGE("Could not initialize the abuffer filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* Create m_AudioFilter.volume filter. */
    m_AudioFilter.volume = avfilter_get_by_name("volume");
    if (!m_AudioFilter.volume) {
        LOGE("Could not find the volume filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    m_AudioFilter.volume_ctx = avfilter_graph_alloc_filter(m_AudioFilter.filter_graph, m_AudioFilter.volume, "volume");
    if (!m_AudioFilter.volume_ctx) {
        LOGE("Could not allocate the volume instance.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* A different way of passing the options is as key/value pairs in a
     * dictionary. */
    av_dict_set(&options_dict, "volume", volume_buf, 0);
    err = avfilter_init_dict(m_AudioFilter.volume_ctx, &options_dict);
    av_dict_free(&options_dict);
    if (err < 0) {
        LOGE("Could not initialize the volume filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* Create the m_AudioFilter.aformat filter;
     * it ensures that the output is of the format we want. */
    m_AudioFilter.aformat = avfilter_get_by_name("aformat");
    if (!m_AudioFilter.aformat) {
        LOGE("Could not find the aformat filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    m_AudioFilter.aformat_ctx = avfilter_graph_alloc_filter(m_AudioFilter.filter_graph, m_AudioFilter.aformat, "aformat");
    if (!m_AudioFilter.aformat_ctx) {
        LOGE("Could not allocate the aformat instance.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* A third way of passing the options is in a string of the form
     * key1=value1:key2=value2.... */
    snprintf(options_str, sizeof(options_str),
             "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64,
             av_get_sample_fmt_name(out_format), out_sample_rate,
             (uint64_t)out_channel_layout);
    err = avfilter_init_str(m_AudioFilter.aformat_ctx, options_str);
    if (err < 0) {
        LOGE("Could not initialize the aformat filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }
    /* Finally create the m_AudioFilter.abuffersink filter;
     * it will be used to get the filtered data out of the graph. */
    m_AudioFilter.abuffersink = avfilter_get_by_name("abuffersink");
    if (!m_AudioFilter.abuffersink) {
        LOGE("Could not find the abuffersink filter.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    m_AudioFilter.abuffersink_ctx = avfilter_graph_alloc_filter(m_AudioFilter.filter_graph, m_AudioFilter.abuffersink, "sink");
    if (!m_AudioFilter.abuffersink_ctx) {
        LOGE("Could not allocate the abuffersink instance.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* This filter takes no options. */
    err = avfilter_init_str(m_AudioFilter.abuffersink_ctx, NULL);
    if (err < 0) {
        LOGE("Could not initialize the abuffersink instance.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* Connect the filters;
     * in this simple case the filters just form a linear chain. */
    err = avfilter_link(m_AudioFilter.abuffer_ctx, 0, m_AudioFilter.volume_ctx, 0);
    if (err >= 0)
        err = avfilter_link(m_AudioFilter.volume_ctx, 0, m_AudioFilter.aformat_ctx, 0);
    if (err >= 0)
        err = avfilter_link(m_AudioFilter.aformat_ctx, 0, m_AudioFilter.abuffersink_ctx, 0);
    if (err < 0) {
        LOGE("Error connecting filters.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    /* Configure the graph. */
    err = avfilter_graph_config(m_AudioFilter.filter_graph, NULL);
    if (err < 0) {
        LOGE("Error configuring the filter graph.%s", FFERR2STR(ENOMEM));
        goto failed;
    }

    // LOGD("graph dump:%s", avfilter_graph_dump(m_AudioFilter.filter_graph, NULL));

    return 0;

failed:
	avfilter_graph_free(&m_AudioFilter.filter_graph);

    return -1;
}

void MediaPlayer::registerVideoDisplayCB(videodisplay_callback video_discb, void *ctx)
{
	LOGI("registerVideoDisplayCB(cb:%p, para:%p)", video_discb, ctx);
	m_VideoDisCB = video_discb;
	m_VideoDisPara = ctx;
}

void MediaPlayer::registerVideoInitCB(videoinit_callback video_init, void *ctx)
{
	LOGI("registerVideoInitCB(cb:%p, para:%p)", video_init, ctx);
	m_VideoInitCB = video_init;
	m_VideoInitPara = ctx;
}

void MediaPlayer::registerAudioOutCB(audioout_callback audio_outcb, void *ctx)
{
	LOGI("registerAudioOutCB(cb:%p, para:%p)", audio_outcb, ctx);
	m_AudioOutCB = audio_outcb;
	m_AudioOutPara = ctx;
}

void MediaPlayer::registerAudioOperateCB(Audio_Operate_Func operate, audio_operate_callback func, void *lpara)
{
	LOGI("registerAudioCB operate:%d func:%p para:%p", operate, func, lpara);
	switch(operate) {
		case Audio_Operate_Init:
			m_AudioFuncInit = func;
			m_AudioInitPara = lpara;
			break;
		case Audio_Operate_Pause:
			m_AudioFuncPause = func;
			break;
		case Audio_Operate_Play:
			m_AudioFuncPlay = func;
			break;
		case Audio_Operate_Flush:
			m_AudioFuncFlush = func;
			break;
		case Audio_Operate_SetSpeed:
			m_AudioFuncSetSpeed = func;
			break;
		case Audio_Operate_GetBufferDuration:
			m_AudioFuncGetBufferDuration = func;
			break;
		default:
			LOGE("unkown operate!");
	}
	m_AudioCBPara = lpara; 
}

void MediaPlayer::registerEventCB(event_callback eventcb, void *ctx)
{
	LOGI("registerEventCB(cb:%p, para:%p)", eventcb, ctx);
	m_EventCB = eventcb;
	m_EventPara = ctx;
}

int MediaPlayer::videoDecodeThread(void *lpara)
{
	MediaPlayer *player = (MediaPlayer *)lpara;
	player->video_decode();
	return 0;
}

int MediaPlayer::video_decode()
{
	int ret = 0, got_picture = 0;
	AVFrame *frame = av_frame_alloc();
	Frame *vp = NULL;
	AVRational tb = m_PDemux->m_VideoTimeBase;
	int serial;
	while(true) {
		got_picture = m_PVideoDecoder->decode(frame);
		//receive abort signal from packetqueue, exit
		if(got_picture < 0)
			break;
		if(got_picture == 1) {
			vp = m_PVideoFrameQueue->waitForWritable();
			if(!vp)
				break;

			/*将一帧的时长和pts转换为秒*/
			vp->duration = (tb.num && tb.den ? av_q2d(tb) : 0);
            vp->pts = (frame->pts != AV_NOPTS_VALUE && tb.num && tb.den) ? frame->pts * av_q2d(tb) : NAN;
            vp->serial = m_PVideoPacketQueue->m_Serial;
			av_frame_move_ref(vp->frame, frame);
			m_PVideoFrameQueue->push();
		}

	}
	return 0;
}

int MediaPlayer::audioDecodeThread(void *lpara)
{
	MediaPlayer *player = (MediaPlayer *)lpara;
	player->audio_decode();
	return 0;
}

int MediaPlayer::audio_decode()
{
	// MediaPlayer *player = (MediaPlayer *)lpara;
	int ret = 0, got_frame = 0;
	AVPacket read_pkt;
	AVFrame *frame = av_frame_alloc();
	Frame *vp = NULL;
	AVRational tb = m_PDemux->m_AudioTimeBase;
	int serial;
	while(true) {

		//需要缓存
		if(m_PAudioPacketQueue->isEmpty()) {
			// pause();
		}

		got_frame = m_PAudioDecoder->decode(frame);
		//receive abort signal from packetqueue, exit
		if(got_frame < 0)
			break;
		if(got_frame == 1) {
			//LOGD("audio decode frame pts:%lld pktsize:%d", frame->pts, m_PAudioPacketQueue->nb_pkt());
			vp = m_PAudioFrameQueue->waitForWritable();
			if(!vp)
				break;

			/*将一帧的时长和pts转换为秒*/
			vp->duration = (tb.num && tb.den ? av_q2d(tb) : 0);
            vp->pts = (frame->pts != AV_NOPTS_VALUE && tb.num && tb.den) ? frame->pts * av_q2d(tb) : NAN;
            // LOGD("vp->pts:%03f", vp->pts);
            vp->serial = m_PAudioPacketQueue->m_Serial;

			av_frame_move_ref(vp->frame, frame);
			m_PAudioFrameQueue->push();
		}

	}
	return 0;
}

int MediaPlayer::audioOutThread(void *lpara)
{
	MediaPlayer *player = (MediaPlayer *)lpara;
	player->audio_out();
	return 0;
}

int MediaPlayer::audio_out()
{
	audioout_callback audio_play = m_AudioOutCB;
	Frame *pFrame;
	AVFrame *pAVFrame;
    AVFilterGraph *graph;
    AVFilterContext *src, *sink;

    int err = 0;
    char errbuf[100];

	m_AudioFmt = m_PlayerOpt.audio_out_format;
	m_AudioChannelLayout = m_PlayerOpt.audio_out_channel_layout;
	m_AudioSampleRate = m_PlayerOpt.audio_out_sample_rate;
	m_Channels = av_get_channel_layout_nb_channels(m_AudioChannelLayout);
	while(true) {
		if(m_PlayerAbortRequest)
			break;

        if(m_PauseRequest || m_AudioPktUnderrun) {
        	usleep(10000);
        	continue;
        }

        pFrame = getAudioFrame();
        if(!pFrame)
        	continue;
        pAVFrame = pFrame->frame;
        if(!pAVFrame)
        	continue;
	    // LOGV("a:%5dKb %7.3fs %5d v:%5dKb %7.3fs %5d",\
	    //  getPropertyInt(Player_Property_Int_AudioCachedBytes)/1024, 
	    //  (float)getPropertyInt(Player_Property_Int_AudioCachedDuration)/90000,
	    //  m_PAudioPacketQueue->nb_pkt(),
	    //  getPropertyInt(Player_Property_Int_VideoCachedBytes)/1024, 
	    //  (float)getPropertyInt(Player_Property_Int_VideoCachedDuration)/90000,
	    //  m_PVideoPacketQueue->nb_pkt());
 
	    if(!m_PAudioSink) {
	    	m_PAudioSink = new AlsaAudioSink();
	    	int nb_samples = getPropertyInt(Player_Property_Int_AudioFrameSize);
	    	err = m_PAudioSink->init(SND_PCM_FORMAT_S16_LE, m_AudioSampleRate, m_Channels, nb_samples);
		    if(err != 0) {
		    	LOGE("init_audio failed");
		    }
	    }

	    int64_t dec_channel_layout =
	        (pAVFrame->channel_layout && pAVFrame->channels == av_get_channel_layout_nb_channels(pAVFrame->channel_layout)) ?
	        pAVFrame->channel_layout : av_get_default_channel_layout(pAVFrame->channels);

	    //播放过程中若音频变化，重新初始化swr_ctx重采样
	    if (pAVFrame->format        != m_AudioFmt           ||
	        dec_channel_layout      != m_AudioChannelLayout ||
	        pAVFrame->sample_rate   != m_AudioSampleRate    ||
	        !m_AudioFilter.filter_graph)
	    {
	    	//(input) -> abuffer -> volume -> aformat -> abuffersink -> (output)
			//使用libavfilter重采样,初始化音频滤镜图，volume用于调节音量,播放中途音频参数变化时重新初始化
	        if(m_AudioFilter.filter_graph)
	        	avfilter_graph_free(&m_AudioFilter.filter_graph);
	        err = initAudioFilterGraph(pAVFrame->sample_rate, pAVFrame->format, dec_channel_layout, 
	        	                       m_PlayerOpt.audio_out_sample_rate, m_PlayerOpt.audio_out_format,
	        	                       m_PlayerOpt.audio_out_channel_layout);
			if(err) {
				LOGE("initAudioFilterGraph failed!");
				return -1;
			}
			graph = m_AudioFilter.filter_graph;
			src = m_AudioFilter.abuffer_ctx;
			sink = m_AudioFilter.abuffersink_ctx;
			if(!graph || !src || !sink) {
				LOGE("AudioFilter Error, graph(%p) src(%p) sink(%p)", graph, src, sink);
				return -1;
			}
			int out_channels = av_get_channel_layout_nb_channels(m_PlayerOpt.audio_out_channel_layout);

			LOGD("Create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!",
                    pAVFrame->sample_rate, av_get_sample_fmt_name(pAVFrame->format), pAVFrame->channels,
                    m_PlayerOpt.audio_out_sample_rate, av_get_sample_fmt_name(m_PlayerOpt.audio_out_format), out_channels);

	        m_AudioChannelLayout = dec_channel_layout;
	        m_Channels           = pAVFrame->channels;
	        m_AudioSampleRate    = pAVFrame->sample_rate;
	        m_AudioFmt           = pAVFrame->format;
	    }

        /* 调节音量 重采样*/
        /* Send the frame to the input of the filtergraph. */
        err = av_buffersrc_add_frame(src, pAVFrame);
        if (err < 0) {
            av_frame_unref(pAVFrame);
            LOGE("Error submitting the frame to the filtergraph:%s", FFERR2STR(ENOMEM));
            goto fail;
        }

        /* Get all the filtered output that is available. */
        while ((err = av_buffersink_get_frame(sink, pAVFrame)) >= 0) {
		    int planar     = av_sample_fmt_is_planar(pAVFrame->format);
		    int channels   = av_get_channel_layout_nb_channels(pAVFrame->channel_layout);
		    int planes     = planar ? channels : 1;
		    int bps        = av_get_bytes_per_sample(pAVFrame->format);
		    int plane_size = bps * pAVFrame->nb_samples * (planar ? 1 : channels);

		    /*播放声音*/
		    if(m_PAudioSink) {
		    	m_PAudioSink->playFrame(pAVFrame->data[0], pAVFrame->nb_samples);
		    }

		    if(!m_FirstAudioRendered) {
		    	postEvent(Player_Evt_AudioRenderStart);
		    	m_FirstAudioRendered = true;
		    }

		    //获取缓存中的buffer时长
		    double buffer_duration = m_PAudioSink->getBufferDuration();

		    //用于音视频同步
		    setAudioPts(pFrame->pts - buffer_duration);
            av_frame_unref(pAVFrame);
        }

        if (err == AVERROR(EAGAIN)) {
            /* Need to feed more frames in. */
            continue;
        } else if (err == AVERROR_EOF) {
            /* Nothing more to do, finish. */
            break;
        } else if (err < 0) {
            /* An error occurred. */
            LOGE("Error filtering the data:%s", FFERR2STR(ENOMEM));
            goto fail;
        }
	}
fail:
	return 0;

}

int MediaPlayer::videoRefreshThread(void *lpara)
{
	MediaPlayer *player = (MediaPlayer *)lpara;
	player->video_refresh();
	return 0;
}

#define REFRESH_RATE 0.01  //不能低于帧率
int MediaPlayer::video_refresh()
{
	videodisplay_callback video_display = m_VideoDisCB;
	int cnt = 0;
	double delay = 0.0;
	int src_width = getPropertyInt(Player_Property_Int_VideoWidth);
	int src_height = getPropertyInt(Player_Property_Int_VideoHeight);
	while(true){

		if(m_PlayerAbortRequest)
			break;

        if(m_PauseRequest) {
        	// goto display;
        	usleep(10000);
        	continue;
        }
        //
        usleep(1000);

        //上一帧显示的时间
        static double last_timer = 0;// = av_gettime_relative() / 1000000.0;
        // LOGD("m_PVideoFrameQueue->unDisplayFrame():%d", m_PVideoFrameQueue->unDisplayFrame());

		if(m_PVideoFrameQueue->unDisplayFrame() != 0) {

retry:
			Frame *lastvp, *vp;
			lastvp = m_PVideoFrameQueue->peekLast(); //上一帧
			vp = m_PVideoFrameQueue->peek(); //当前待显示帧

			//一个新的操作序列(seek)会修改serial值，不等则需要将上一个操作序列的frame丢弃
			if(vp->serial != m_PVideoPacketQueue->m_Serial) {
				// LOGI("video vp->serial:%d m_PVideoFrameQueue->m_Serial:%d", vp->serial, m_PVideoPacketQueue->m_Serial);
				//读指针加一，下一次peek时会指向下一个frame
				m_PVideoFrameQueue->next();
				goto retry;
			}

			//理论上上一帧应该显示的时间
			double last_duration = vp->pts - lastvp->pts;
			//音视频PTS的差值（秒为单位）
			double diff = lastvp->pts - m_CurrentAudioPts;

			// LOGD("av-diff:%5.3fs %5.3fs %5.3fs a:%5dKb %5.3fs %5d v:%5dKb %5.3fs %5d delay:%5.3f   ",\
			// 		     diff, lastvp->pts, m_CurrentAudioPts,
			// 		     getPropertyInt(Player_Property_Int_AudioCachedBytes)/1024, 
			// 		     (float)getPropertyInt(Player_Property_Int_AudioCachedDuration)/90000,
			// 		     m_PAudioPacketQueue->nb_pkt(),
			// 		     getPropertyInt(Player_Property_Int_VideoCachedBytes)/1024, 
			// 		     (float)getPropertyInt(Player_Property_Int_VideoCachedDuration)/90000,
			// 		     m_PVideoPacketQueue->nb_pkt(),delay);

			//视频流切换时，diff可能会很大，跳过
			if(fabs(diff) > 2.0) {
				goto display;
			}

			//暂停恢复时此值也可能会很大
		    if(diff >= 0.1) {
		    	usleep(10000);
		    	continue;
		    }

		    delay = REFRESH_RATE;
		    if (!isnan(diff)) {
		        if (diff <= 0.0)
		            delay = FFMAX(0, last_duration + diff); //音频超前，视频滞后，delay减小
		        else
		        	delay = diff;
		    }

		    usleep((int64_t)(delay * 1000000.0));

display:
			m_PVideoFrameQueue->next();

			lastvp = m_PVideoFrameQueue->peekLast();
			//更新显示时间
			last_timer = av_gettime_relative() / 1000000.0;

			AVFrame *frame = lastvp->frame;
			// LOGD(" %dx%d  %dx%d", src_width, src_height, frame->width, frame->height);

			if(frame->width != src_width || frame->height != src_height) {
				LOGD("video changed %dx%d -> %dx%d", src_width, src_height, frame->width, frame->height);
				src_width = frame->width;
				src_height = frame->height;
				postEvent(Player_Evt_VideoChanged);
			}

			displayImage(lastvp);

		    if(!m_FirstVideoRendered) {
		    	postEvent(Player_Evt_VideoRenderStart);
		    	m_FirstVideoRendered = true;
		    }

		    static int prev_time=0, cur_time, diff_time;

		    cur_time = av_gettime_relative();

			LOGV("av-diff:%5.3fs %5.3fs %5.3fs a:%5dKb %5.3fs %5d v:%5dKb %5.3fs %5d lasttime:%5.3fs delay:%5.3f",\
					     diff, lastvp->pts, m_CurrentAudioPts,
					     getPropertyInt(Player_Property_Int_AudioCachedBytes)/1024, 
					     (float)getPropertyInt(Player_Property_Int_AudioCachedDuration)/90000,
					     m_PAudioPacketQueue->nb_pkt(),
					     getPropertyInt(Player_Property_Int_VideoCachedBytes)/1024, 
					     (float)getPropertyInt(Player_Property_Int_VideoCachedDuration)/90000,
					     m_PVideoPacketQueue->nb_pkt(),(double)(cur_time - prev_time) / 1000000.0, delay);

			AVRational audioTb = m_PDemux->m_AudioTimeBase;
			AVRational videoTb = m_PDemux->m_VideoTimeBase;

		    prev_time = cur_time;
		}
	}
	return 0;
}

void MediaPlayer::setDisplayArea(int x, int y, int w, int h)
{
	if(!m_PVideoSink) {
		LOGE("m_PVideoSink is null");
		return;
	}
	m_PVideoSink->setDisplayArea(x, y, w, h);
}

int MediaPlayer::displayImage(Frame *vframe)
{
	AVFrame *frame = vframe->frame;
	int ret;

	//delete videoSink时会close drm,关闭视频图层
	if(m_VideoHide && m_PVideoSink) {
		delete m_PVideoSink;
		m_PVideoSink = NULL;
	}

	if(!m_PVideoSink && !m_VideoHide) {
#ifdef RK
		m_PVideoSink = new DRMVideoSink();
#else
		m_PVideoSink = new SDLVideoSink();
	    ret = m_PVideoSink->init(frame->width, frame->height, frame->width, frame->height, AV_PIX_FMT_NV12);
	    if(ret) {
	    	LOGE("m_PVideoSink initial error");
	    }
#endif
		//m_PVideoSink->dumpPicture("/app/chendilin/dump.yuv", 0, 1);
	}

#ifdef RK
	//rkmppdec.c中赋值
	int *stride = (int *)frame->opaque;
	int horstride = stride[0];
	int verstride = stride[1];

	if(horstride == frame->width && verstride == frame->height) {
		horstride = stride[2];
		verstride = stride[3];
	}

	if(m_PVideoSink && !m_PVideoSink->isInited()) {
		LOGI("m_PVideoSink init %dx%d %dx%d (stride:%d %d %d %d)", horstride, verstride, 
			frame->width, frame->height, stride[0], stride[1], stride[2], stride[3]);
	    //rk3328 mpp解码后固定NV12格式
	    ret = m_PVideoSink->init(frame->width, frame->height, horstride, verstride, AV_PIX_FMT_NV12);
	    if(ret) {
	    	LOGE("m_PVideoSink initial error");
	    }
	    if(m_PlayerOpt.keep_video_ratio)
	    	m_PVideoSink->keepRatio(true);
	    m_PVideoSink->setDisplayArea(16, 154, 1334, 597);
		m_Width = frame->width;
		m_Height = frame->height;
	}
	//视频宽高变化，需重新初始化DRM
	if(m_PVideoSink && (frame->width != m_Width || frame->height != m_Height)) {
		delete m_PVideoSink;
		m_PVideoSink = new DRMVideoSink();
		LOGI("video changed %dx%d -> %dx%d (stride:%d %d %d %d)", m_Width, m_Height, frame->width, frame->height,
			 stride[0], stride[1], stride[2], stride[3]);
	    //rk3328 mpp解码后固定NV12格式
	    ret = m_PVideoSink->init(frame->width, frame->height, horstride, verstride, AV_PIX_FMT_NV12);
	    if(ret) {
	    	LOGE("m_PVideoSink initial error");
	    }
	    if(m_PlayerOpt.keep_video_ratio)
	    	m_PVideoSink->keepRatio(true);
	    m_PVideoSink->setDisplayArea(16, 154, 1334, 597);
		m_Width = frame->width;
		m_Height = frame->height;
	}
#endif
	if(m_PVideoSink) {
		return m_PVideoSink->showFrame(vframe);
	}
	return -1;
}

void MediaPlayer::videoShow()
{
	LOGI("videoShow");
	m_VideoHide = false;
}

void MediaPlayer::videoHide()
{
	LOGI("videoHide");
	m_VideoHide = true;
}

Frame *MediaPlayer::getAudioFrame()
{
	// LOGD("get audio start");
	Frame *vp;

	do {
		vp = m_PAudioFrameQueue->waitForReadable();

		if(!vp)
			return NULL;

		m_PAudioFrameQueue->next();
		if(vp->serial != m_PAudioPacketQueue->m_Serial)
			LOGD("audio vp->serial:%d m_PAudioPacketQueue->m_Serial:%d", vp->serial, m_PAudioPacketQueue->m_Serial);
		
	}while(vp->serial != m_PAudioPacketQueue->m_Serial);

	// LOGD("get audio leave");
	return vp;
}

/*
	lpara:
		Pause/Play/Flush:NULL
		SetVolume/SetSpeed:int *, float *
*/
void MediaPlayer::audioOperate(Audio_Operate_Func operate, void *lpara)
{
	audio_operate_callback audioPause = m_AudioFuncPause;
	audio_operate_callback audioPlay = m_AudioFuncPlay;
	audio_operate_callback audioFlush = m_AudioFuncFlush;
	audio_operate_callback audioSetSpeed = m_AudioFuncSetSpeed;
	audio_operate_callback audioGetBufferDuration = m_AudioFuncGetBufferDuration;
	switch(operate) {
		case Audio_Operate_Pause:
			if(audioPause)
				audioPause(m_AudioCBPara, lpara);
			else
				LOGW("unregister function pause!");
			break;
		case Audio_Operate_Play:
			if(audioPlay)
				audioPlay(m_AudioCBPara, lpara);
			else
				LOGW("unregister function play!");
			break;
		case Audio_Operate_Flush:
			if(audioFlush)
				audioFlush(m_AudioCBPara, lpara);
			else
				LOGW("unregister function flush!");
			break;
		case Audio_Operate_SetSpeed:
			if(audioSetSpeed)
				audioSetSpeed(m_AudioCBPara, lpara);
			else
				LOGW("unregister function setspeed!");
			break;
		case Audio_Operate_GetBufferDuration: {
				double delay;
				if(audioGetBufferDuration) {
					audioGetBufferDuration(m_AudioCBPara, &delay);
					*(double *)lpara = delay;
				}
				else
					LOGW("unregister function getBufferDuration!");
				break;
			}
		default:
			LOGW("unkown operate!");
	}
}

void MediaPlayer::setAudioPts(double pts)
{
	m_CurrentAudioPts = pts;
}

void MediaPlayer::logCallBack(void *ptr, int level, const char *fmt, va_list vl)
{
	if (level > av_log_get_level())
		return;

	va_list vl2;
	char line[1024];
	static int print_prefix = 1;

	va_copy(vl2, vl);
	av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
	va_end(vl2);

	int size = strlen(line);
	if(line[size - 1] == '\n') {
		line[size - 1] = ' ';
	}

	switch(level) {
		case AV_LOG_DEBUG:
			LOGD("%s", line);
			break;
		case AV_LOG_VERBOSE:
			LOGV("%s", line);
			break;
		case AV_LOG_INFO:
			LOGI("%s", line);
			break;
		case AV_LOG_WARNING:
			LOGW("%s", line);
			break;
		case AV_LOG_ERROR:
			LOGE("%s", line);
			break;
		case AV_LOG_FATAL:
			LOGE("%s", line);
			break;
		default:
			LOGD("%s", line);
	}

}